/*-------------------------------------------------------------------------
 - Copyright (c) 2024-2025 [XD-AMCC TEAM]
 - [XD-AMCC] is licensed under Mulan PSL v2.
 - You can use this software according to the terms and conditions of the Mulan PSL v2.
 - You may obtain a copy of Mulan PSL v2 at:
 -          http://license.coscl.org.cn/MulanPSL2
 - THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
 - OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 - TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 - See the Mulan PSL v2 for more details.
 ------------------------------------------------------------------------*/

/**
 * @brief Inner operations of the class IR-codes emitter.
 *
 * @author  WXQ#XDU
 * @date    2025.01
 */

#include "_emit_inner.h"

static void emitter_popFuncInfo(t_emitter_ptr);
static t_emitter_funcinfo * emitter_pushFuncInfo(t_emitter_ptr, t_tree_ptr);


void emitter_entry_func(t_emitter_ptr pThis, t_tree_ptr funcDeclNode) {
    emitter_pushFuncInfo(pThis, funcDeclNode);
    codemgr_entry_func( pThis->ircodemgrPtr, funcDeclNode);
}

void emitter_exit_func(t_emitter_ptr pThis) {
    codemgr_exit_func( pThis->ircodemgrPtr );
    emitter_popFuncInfo(pThis);
}



//  ---------  Following code are helpers --------------------------


static t_hashcode mapfunc_keyhash_(t_map_key labelName) {
    return amcc_hashcode((const char*)labelName);
}

static int mapfunc_keycomp_ (t_map_key labelName1, t_map_key labelName2) {
    return strcmp((char*)labelName1, (char*)labelName2);
}

static void  free_chainOfLabel_(t_map_key labelName, t_map_value value) {
    t_list_ptr  chain = (t_list_ptr)value;
    list_destroy(chain);
}

static void free_ir_code_(t_list_app_value ircode){
    t_ircode_ptr codePtr = (t_ircode_ptr) ircode;
    if (0 == codePtr->comment.isConstant)
        return;

    free( (char*) (codePtr->comment.text));  //  destroy comment of ir-code
    codePtr->comment.text = NULL;
}


/**
 * @brief  Pop from emitter.functionStack.
 *
 * This function is called when emitter exits from a function scope.
 *
 * @param pThis      pointer to this emitter
 */
static void emitter_popFuncInfo(t_emitter_ptr pThis) {
    stack_pop( &pThis->functionStack );
    if (NULL != pThis->currFuncInfo) {
        hashmap_destroy( pThis->currFuncInfo->chainOfLabels );  // will call free_chainOfLable_()
        hashmap_destroy( pThis->currFuncInfo->targetOfLabels );

        if (NULL != pThis->currFuncInfo->ircodes)
            list_destroy( pThis->currFuncInfo->ircodes );
        free(pThis->currFuncInfo);
    }

    pThis->currFuncInfo = (t_emitter_funcinfo *)stack_top( &pThis->functionStack );
}


/**
 * @brief  Create and Push a func-info into emitter.functionStack.
 *
 * This function is called when emitter enters into a function scope.
 *
 * @param pThis          pointer to this emitter
 * @param funcDeclNode  tree root of a function definition
 *                       (marked by funcDeclaration or translationUnit)
 *
 * @return pointer to the new func-info object.
 */
static t_emitter_funcinfo * emitter_pushFuncInfo(t_emitter_ptr pThis, t_tree_ptr funcDeclNode) {
    t_emitter_funcinfo *
    funcinfo = (t_emitter_funcinfo*)calloc(1, sizeof(*funcinfo));

    funcinfo->funcDeclNode   = funcDeclNode;
    funcinfo->nextCodeId     = 1;
    funcinfo->ircodes        = list_new( free_ir_code_ );
    funcinfo->targetOfLabels = hashmap_new(5, mapfunc_keyhash_,
                                mapfunc_keycomp_, NULL);
    funcinfo->chainOfLabels  = hashmap_new(5, mapfunc_keyhash_,
                                mapfunc_keycomp_, free_chainOfLabel_);

    // this data will be destroyed by emitter_popFuncInfo()
    stack_push( & pThis->functionStack , funcinfo );
    pThis->currFuncInfo = funcinfo;
    return funcinfo;
}

